package com.itcz.maker.generator.main;

import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.core.util.ZipUtil;
import com.itcz.maker.generator.JarGenerator;
import com.itcz.maker.generator.ScriptGenerator;
import com.itcz.maker.generator.file.DynamicFileGenerator;
import com.itcz.maker.meta.Meta;
import com.itcz.maker.meta.MetaManager;
import freemarker.template.TemplateException;

import java.io.File;
import java.io.IOException;

/**
 * 制作代码生成器
 */
public abstract class MakeGenerator {
    public void doGenerate() throws TemplateException, IOException, InterruptedException{
        Meta meta = MetaManager.getMetaObject();
        // 获取项目根目录
        String projectPath = System.getProperty("user.dir");
        String outputPath = projectPath + File.separator + "generated" + File.separator + meta.getName();

        // 制作代码生成器
        doGenerate(meta, outputPath);
    }

    public void doGenerate(Meta meta,
                           String outputPath
    ) throws TemplateException, IOException, InterruptedException{
        // 通过Hutool工具包查找目录是否存在
        if(!FileUtil.exist(outputPath)) {
            // 不存在，则通过Hutool工具包创建文件和目录
            FileUtil.mkdir(outputPath);
        }

        // 1.复制资源文件
        String sourceCopyDestPath = copySource(meta, outputPath);

        // 2.生成代码文件
        generateCode(meta, outputPath);

        // 3.构建jar包
        String jarPath = buildJar(outputPath, meta);

        // 4.封装脚本文件
        String shellOutputPath = buildScript(outputPath, jarPath);

        // 5.生成精简版的程序（产物包）
        buildDist(outputPath, sourceCopyDestPath, jarPath, shellOutputPath);
    }

    /**
     * 生成精简版的程序（产物包）
     * @param outputPath
     * @param sourceCopyDestPath
     * @param jarPath
     * @param shellOutputPath
     * @return
     */
    protected String buildDist(String outputPath, String sourceCopyDestPath, String jarPath, String shellOutputPath) {
        String distOutputPath  = outputPath + "-dist";
        // -拷贝jar包
        String targetAbsolutePath = distOutputPath + File.separator + "target";
        FileUtil.mkdir(targetAbsolutePath);
        String jarAbsolutePath = outputPath + File.separator + jarPath;
        FileUtil.copy(jarAbsolutePath,targetAbsolutePath, true);
        // -拷贝脚本文件
        FileUtil.copy(shellOutputPath, distOutputPath, true);
        FileUtil.copy(shellOutputPath + ".bat", distOutputPath, true);
        // -拷贝原模板目录.source
        FileUtil.copy(sourceCopyDestPath, distOutputPath, true);
        return distOutputPath;
    }

    /**
     * 构建脚本文件
     * @param outputPath
     * @param jarPath
     * @return
     */
    protected String buildScript(String outputPath, String jarPath) {
        String shellOutputPath = outputPath + File.separator + "generator";
        ScriptGenerator.doGenerate(shellOutputPath, jarPath);
        return shellOutputPath;
    }

    /**
     * 构建Jar包
     * @param outputPath
     * @param meta
     * @return
     * @throws IOException
     * @throws InterruptedException
     */
    protected String buildJar(String outputPath, Meta meta) throws IOException, InterruptedException {
        String jarName = String.format("%s-%s-jar-with-dependencies.jar", meta.getName(), meta.getVersion());
        String jarPath = "target/" + jarName;
        JarGenerator.doGenerate(outputPath);
        return jarPath;
    }

    /**
     * 根据ftl模板文件生成对应的文件
     * @param meta
     * @param outputPath
     * @throws IOException
     * @throws TemplateException
     */
    protected void generateCode(Meta meta, String outputPath) throws IOException, TemplateException {
        String inputPath = "";

        // Java 包基础路径
        String outputBasePackage = meta.getBasePackage();
        // 将包中.转换成路径中的/
        // 使用Hutool工具包通过.将字符串分割成List对象,再通过String.join()将List集合中每个数据用/连接成字符串
        String outputBasePackagePath = String.join("/", StrUtil.split(outputBasePackage, "."));
        String outputBaseJavaPackagePath = outputPath + File.separator + "src/main/java/" + outputBasePackagePath;

        String inputFilePath;
        String outputFilePath;

        // model.DataModel.java
        // 数据模型输入路径
        inputFilePath = inputPath + File.separator + "templates/java/model/DataModel.java.ftl";
        // 生成文件输出路径
        outputFilePath = outputBaseJavaPackagePath + File.separator + "model/DataModel.java";
        // 动态生成文件
        DynamicFileGenerator.doGenerate(inputFilePath, outputFilePath, meta);

        // generator.MainGenerator.java
        inputFilePath = inputPath + File.separator + "templates/java/generator/MainGenerator.java.ftl";
        outputFilePath = outputBaseJavaPackagePath + File.separator + "generator/MainGenerator.java";
        DynamicFileGenerator.doGenerate(inputFilePath, outputFilePath, meta);

        // cli.command.GeneratorCommand.java
        inputFilePath = inputPath + File.separator + "templates/java/cli/command/GeneratorCommand.java.ftl";
        outputFilePath = outputBaseJavaPackagePath + File.separator + "cli/command/GeneratorCommand.java";
        DynamicFileGenerator.doGenerate(inputFilePath, outputFilePath, meta);

        // cli.command.JsonGeneratorCommand.java
        inputFilePath = inputPath + File.separator + "templates/java/cli/command/JsonGeneratorCommand.java.ftl";
        outputFilePath = outputBaseJavaPackagePath + File.separator + "cli/command/JsonGeneratorCommand.java";
        DynamicFileGenerator.doGenerate(inputFilePath, outputFilePath, meta);

        // cli.command.ListCommand.java
        inputFilePath = inputPath + File.separator + "templates/java/cli/command/ListCommand.java.ftl";
        outputFilePath = outputBaseJavaPackagePath + File.separator + "cli/command/ListCommand.java";
        DynamicFileGenerator.doGenerate(inputFilePath, outputFilePath, meta);

        // cli.command.ConfigCommand.java
        inputFilePath = inputPath + File.separator + "templates/java/cli/command/ConfigCommand.java.ftl";
        outputFilePath = outputBaseJavaPackagePath + File.separator + "cli/command/ConfigCommand.java";
        DynamicFileGenerator.doGenerate(inputFilePath, outputFilePath, meta);

        // cli.CommandExecutor.java.ftl
        inputFilePath = inputPath + File.separator + "templates/java/cli/CommandExecutor.java.ftl";
        outputFilePath = outputBaseJavaPackagePath + File.separator + "cli/CommandExecutor.java";
        DynamicFileGenerator.doGenerate(inputFilePath, outputFilePath, meta);

        // Main.java
        inputFilePath = inputPath + File.separator + "templates/java/Main.java.ftl";
        outputFilePath = outputBaseJavaPackagePath + File.separator + "Main.java";
        DynamicFileGenerator.doGenerate(inputFilePath, outputFilePath, meta);

        // generator.DynamicGenerator.java
        inputFilePath = inputPath + File.separator + "templates/java/generator/DynamicGenerator.java.ftl";
        outputFilePath = outputBaseJavaPackagePath + File.separator + "generator/DynamicGenerator.java";
        DynamicFileGenerator.doGenerate(inputFilePath, outputFilePath, meta);

        // generator.StaticGenerator.java
        inputFilePath = inputPath + File.separator + "templates/java/generator/StaticGenerator.java.ftl";
        outputFilePath = outputBaseJavaPackagePath + File.separator + "generator/StaticGenerator.java";
        DynamicFileGenerator.doGenerate(inputFilePath, outputFilePath, meta);

        // pom.xml
        inputFilePath = inputPath + File.separator + "templates/pom.xml.ftl";
        outputFilePath = outputPath + File.separator + "pom.xml";
        DynamicFileGenerator.doGenerate(inputFilePath, outputFilePath, meta);

        // 生成REMEAD.md介绍文件
        inputFilePath = inputPath + File.separator + "templates/REMEAD.md.ftl";
        outputFilePath = outputPath + File.separator + "REMEAD.md";
        DynamicFileGenerator.doGenerate(inputFilePath, outputFilePath, meta);
    }

    /**
     * 复制原始文件到资源目录
     * @param meta
     * @param outputPath
     * @return
     */
    protected String copySource(Meta meta, String outputPath) {
        String sourceRootPath = meta.getFileConfig().getSourceRootPath();
        String sourceCopyDestPath = outputPath + File.separator + ".source";
        // Hutool工具类复制文件
        FileUtil.copy(sourceRootPath, sourceCopyDestPath, true);
        return sourceCopyDestPath;
    }

    /**
     * 制作压缩包
     *
     * @param outputPath
     * @return 压缩包文件地址
     */
    protected String buildZip(String outputPath) {
        // 压缩包文件输出地址
        String zipPath = outputPath + ".zip";
        // 使用Hutool工具包压缩文件
        ZipUtil.zip(outputPath, zipPath);
        return zipPath;
    }
}
